package com.berchen.日期;

import org.junit.Test;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;

/**
 * java7 都有安全问题。
 *  java.time包下的API，操作日期、时间  线程安全的
 *  LocalDate：表示日期
 *  LocalTime：表示时间
 *  LocalDateTime：表示时间和日期
 *
 *  Instant：时间戳（以Unix 元年：1970年1月1日 00:00:00 - 现在的毫秒值）
 *
 *  Duration：计算两个时间之间的间隔
 *  Period：计算两个日期之间的间隔
 *
 *  TemporalAdjuster：时间矫正器。将日期调整到一个周日或者其他时间。【函数式接口】
 *  TemporalAdjusters：该类通过静态方法提供了大量的常用TemporalAdjuster的实现。
 *
 *  DateTimeFormatter：格式化时间日期
 *
 *  对时区进行操作的几个：
 *  ZonedDate：
 *  ZonedTime：
 *  ZonedDateTime：
 */
public class TestTime {

    @Test
    public void test9(){

        // 先构建时间，然后再将日期时间更改成指定时区的时间 2020-12-09T22:40:13.066-03:00[America/Cuiaba]
        LocalDateTime now1 = LocalDateTime.now();
        ZonedDateTime zonedDateTime = now1.atZone(ZoneId.of("America/Cuiaba"));
        System.out.println(zonedDateTime);

        // 指定时区构建时间 2020-12-09T09:38:34.584
        LocalDateTime now = LocalDateTime.now(ZoneId.of("America/New_York"));
        System.out.println(now);


        // 获取所有时区
        Set<String> set = ZoneId.getAvailableZoneIds();
        set.stream().forEach(System.out::println);

    }

    @Test
    public void test8(){

//        DateTimeFormatter dtf=DateTimeFormatter.ISO_DATE_TIME;  // 2020- 12-09T22:19:15.846 就是这个格式
        DateTimeFormatter dtf=DateTimeFormatter.ISO_DATE;  // 2020-12-09 就是这个格式 只要Date
        LocalDateTime ldt=LocalDateTime.now();
        String format = dtf.format(ldt);
        System.out.println(format);

        // 自定义格式化格式
        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format1 = dtf1.format(ldt);
        System.out.println(format1);    // 2020-12-09 22:21:18

        // 字符串解析成Date类型 第二个参数就是解析的格式
        TemporalAccessor parse = ldt.parse(format1,dtf1);
        System.out.println(parse);
    }

    @Test
    public void test7(){

        LocalDateTime ldt=LocalDateTime.now();
        System.out.println(ldt);

        // 指定月中的天
        LocalDateTime localDateTime = ldt.withDayOfMonth(10);
        System.out.println(localDateTime);

        // 跳转到一周后
        LocalDateTime with = ldt.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
        LocalDateTime with1 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));    // 跳转到这周日
        System.out.println(with);
        System.out.println(with1);


        // 自定义：下一个工作日
        LocalDateTime with2 = ldt.with(l -> {
            LocalDateTime ldt1 = (LocalDateTime) l;

            DayOfWeek dow = ldt1.getDayOfWeek();

            // 这里应该还有周一周二周三周四周天 只是没有写了
            if (dow.equals(DayOfWeek.FRIDAY)) {   // 如果是周五将当前加三天
                return ldt1.plusDays(3);
            } else if (dow.equals(DayOfWeek.SATURDAY)) {    // 周六
                return ldt1.plusDays(2);
            }else {
                return ldt1.plusDays(1);
            }
        });
        System.out.println(with2);
    }

    @Test
    public void test6(){

        LocalDate start=LocalDate.of(2015,10,1);
        LocalDate end=LocalDate.now();

        // 计算两日期之间的间隔
        Period between = Period.between(start, end);
        System.out.println(between);
        System.out.println(between.getYears());
        System.out.println(between.getMonths());
        System.out.println(between.getDays());
    }

    @Test
    public void test5() throws InterruptedException {

        Instant start = Instant.now();

        Thread.sleep(1000);
        Instant end = Instant.now();

        // 计算两时间之间的间隔
        Duration between = Duration.between(start, end);
        System.out.println(between.toMillis()); // 转成毫秒值
        System.out.println(between.getSeconds()); // 转成秒值

        LocalTime s=LocalTime.now();
        Thread.sleep(1000);
        LocalTime e=LocalTime.now();

        Duration between1 = Duration.between(s, e);
        System.out.println(between1.toMillis());
        System.out.println(between1.getSeconds());
    }

    @Test
    public void test4(){

        // 获取时间戳 默认获取的是UTC（世界时区）时区的时间  2020-12-09T13:50:31.955Z
        Instant now = Instant.now();
        System.out.println(now);

        // 时区偏移量计算 2020-12-09T21:50:31.955Z+08:00    我们系统与UTC时差为8小时
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);

        // 将时间戳转成毫秒值 1607522118786
        System.out.println(now.toEpochMilli());

        // 从1970-01-01T00:00:00Z 加上600 秒 1970-01-01T00:10:00Z 10分钟
        Instant instant = Instant.ofEpochSecond(600);
        System.out.println(instant);


    }


    @Test
    public void test3(){

        // 获取当前系统的日期与时间 2020-12-09T21:44:11.581
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);

        // 指定时间日期 2015-10-10T13:22:33
        LocalDateTime of = LocalDateTime.of(2015, 10, 10, 13, 22, 33);
        System.out.println(of);

        // plus 加  可以加年月日时分秒
        LocalDateTime localDateTime = now.plusDays(12);
        System.out.println(localDateTime);

        // minus 减 可以减年月日 时分秒
        LocalDateTime localDateTime1 = now.minusDays(8);
        System.out.println(localDateTime1);

        // 获取年 可以获取年月日时分秒
        System.out.println(now.getYear());
        System.out.println(now.getMonthValue());
    }


    // java8  线程安全的
    @Test
    public void test2(){

        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd");

        Callable<LocalDate> call=()-> LocalDate.parse("2020-12-08",dtf);
        ExecutorService pool = Executors.newFixedThreadPool(5);

        List<Future<LocalDate>> list=new ArrayList<>();
        for(int i=0;i<10;i++) {
            Future<LocalDate> submit = pool.submit(call);
            list.add(submit);
        }

        list.stream().forEach(x-> {
            try {
                System.out.println(x.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
        pool.shutdown();    // 关闭池
    }

    /*
    传统的线程使用SimpleDateFormat
     */
    @Test
    public void test1() throws ExecutionException, InterruptedException {

//        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
//        Callable<Date> call=() -> sdf.parse("2020-12-8");     // 会出现线程安全问题
        Callable<Date> call=()->DateFormatThreadLocal.convert("2020-12-8"); // SimpleDateFormat用锁给锁上，避免线程安全问题
        ExecutorService pool = Executors.newFixedThreadPool(5);

        List<Future<Date>> list=new ArrayList<>();
        for(int i=0;i<10;i++) {
            Future<Date> submit = pool.submit(call);
            list.add(submit);
        }

        list.stream().forEach(x-> {
            try {
                System.out.println(x.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
        pool.shutdown();    // 关闭池
    }
}
